#ifndef OBJECTDETECTOR_H
#define OBJECTDETECTOR_H

/********** Library Includes **************************************************/

#include <opencv/cv.h>
#include <opencv/highgui.h>

/********** Local Includes ****************************************************/

#include "blobdetector.h"
#include "robot_structures.h"

/********** Forward Class Declarations ****************************************/

class ImageSource;

/********** Classes ***********************************************************/

class ObjectDetector {
public:
	/**
	 * Creates a new ObjectDetector using the given ImageSource.
	 */
	explicit ObjectDetector(ImageSource *source, bool buffer = true);

	/**
	 * Saves the background image for future use.
	 */
	bool saveBackground();

	cv::Mat getBackground();

	/**
	 * Identifies the obstacles.
	 */
	bool saveObstacles();

	/**
	 * Stores the locations of the robot and fruit for future use.
	 */
	bool saveRobotAndFruit(cv::Point robot, cv::Point fruit, bool debug = false);

	/**
	 * Finds the current location of the robot.
	 */
	RobotOrientation findRobot(bool debug = false);

	/**
	 * Returns a matrix of describing "open" and "blocked" regions.
	 *
	 * The matrix consists of float values (specifically, type CV_32FC1) whose
	 * size is equal to the dimensions of the camera frames.  Each element/pixel
	 * is 1 (indicating that pixel is not obstructed) or 0 (indicating that
	 * pixel is obstructed).
	 */
	cv::Mat & getOpen();

	/**
	 * Returns an image depicting some information gathered by this class for
	 * debugging purposes.
	 */
	cv::Mat processed();

	/**
	 * Returns the last known orientation of the robot.
	 */
	RobotOrientation robot() const;

	/**
	 * Returns the approximate radius of the robot, in pixels.
	 */
	double robotRadius() const;

	/**
	 * Returns the last known position of the robot.
	 */
	cv::Point fruit() const;

private:
	/**
	 * Retrieves the next frame from the ImageSource and blurs it.
	 */
	cv::Mat getAndBlur() const;

	/**
	 * Finds the location of the robot in the given frame.
	 */
	RobotOrientation findRobot(const cv::Mat &frame, bool debug = false);

	/**
	 * Locates the fruit in the frame.
	 *
	 * This method assumes m_obstacles is set to the frame containing the
	 * background and obstacles, and m_fruit is set to the frame containing the
	 * background, obstacles, and fruit.
	 */
	void locateFruit();

	/**
	 * The Euclidean distance between one and two.
	 */
	double euclidean(cv::Point one, cv::Point two) const;

private:
	/**
	 * The source from which to pull camera frames.
	 */
	ImageSource *m_source;

	/**
	 * The frame containing only the background.
	 */
	cv::Mat m_background;

	/**
	 * The frame containing only the background and obstacles.
	 */
	cv::Mat m_obstacles;

	/**
	 * The frame containing only the background, obstacles, and fruit.
	 */
	cv::Mat m_fruit;

	/**
	 * The frame containing the background, obstacles, fruit, and robot.
	 */
	cv::Mat m_robotAndFruit;

	/**
	 * The matrix showing open and blocked pixels (see getOpen()).
	 */
	cv::Mat m_open;

	/**
	 * The difference matrix between m_obstacles and m_robotAndFruit.
	 *
	 * TODO This probably isn't necessary
	 */
	cv::Mat m_rfDiff;

	/**
	 * The last known robot orientation.
	 */
	RobotOrientation m_robotLast;

	/**
	 * The last known fruit position.
	 */
	cv::Point m_fruitLast;

	/**
	 * The blob detector used to calculate the precise position of the robot.
	 */
	BlobDetector m_bd;

	/**
	 * All robot positions, used to draw the robot's path.
	 */
	std::vector<cv::Point> m_breadcrumbs;

	/**
	 * An approximate radius of the robot.
	 */
	double m_robotRadius;

	bool m_buffer;
};

#endif
